keras 소스분석 - fine-tune.py 발표용

2017 12 24일 일요일

오전 2:21

링크: https://deeplearningsandbox.com/how-to-use-transfer-learning-and-fine-tuning-in-keras-and-tensorflow-to-build-an-image-recognition-94b0b02444f2

소스: git clone https://github.com/DeepLearningSandbox/DeepLearningSandbox

 

너무 쉬운걸 이야기 하더라도 이해해주시고,

쉬운 개념 같은데 이해가 안되시는 건 또한 언제든지 인터럽트해서 질문해주세요

 

Transfer Learning

 

1) 이미지넷 이라는 1.2 백만개, 1000 클래스 (=종류) 데이터셋이 있다

2) 이걸로 VGG, GoogLeNet (=Inception), ResNet 등의 CNN 딥러닝 모델들을 학습시키는데는 많은 컴퓨팅 자원과 시간이 소요된다

- 무지막지한 CPU GPU + 2, 3주의 학습시간

3) Keras 에서는 이미 학습된 weight 들을 가진 이런 유명 CNN 모델들을 제공해준다

 

What does the layers learn? 
Edges 
Convolution 
Avg pool 
MaxPool 
Dropout 
Fully connected 
Softmax 
Shapes 
High level features 
Classifers

 

4) 재활용하자

- 위 이미지는 왼쪽에서 입력이 들어와 오른쪽 끝에서 예측하는 것으로 보면 되겠다.

- 여기서 Edges, Shapes 를 추려내는 부분은 재활용이 가능하다는 것이다.

- 맨 끝단만 재학습 시키면 Transfer learning, 여러 상황에 따라 조금 더 거슬러 올라가면 Fine-tune이 되겠다.

* 우리 예제는 일단 Transfer learning 을 통해 Classifier 를 훈련시킨 다음에, Fine-tuning 을 통해 조금 더 위쪽 레이어를 다듬어준다 (learning rate 중요)

 

1. Transfer learning: take a ConvNet that has been pre-trained on ImageNet, 
remove the last fully-connected layer, then treat the rest of the ConvNet as 
a feature extractor for the new dataset. Once you extract the features for 
all images, train a classifier for the new dataset. 
2. Fine-tuning: replace and retrain the classifier on top of the ConvNet, and 
also fine-tune the weights of the pre-trained network via backpropagation.

 

Small dataset 
Large dataset 
Similar dataset 
Transfer learning: 
highest level features 
+ classifier 
Fine-tune* 
Taken from http://cs231n.:ithub.io/ 
Different dataset 
Transfer learning: 
lower level features 
+ classifier 
Fine-tune*

 

 

소스 핵심 분석

- 소스를 단위별로 분석해봄 = 순서는 뒤죽박죽으로 해보겠음

- 결국 181 라인밖에 안되는 소스임

 

train 실행하는 부분

if 
a 
name 
maln 
164 
argument(" - -train_dir") 
argument(" - -val_dir" ) 
166 
167 
168 
173 
171 
172 
173 
174 
175 
176 
177 
178 
179 
181 
argparse. Argument Parser ( ) 
a. add 
a. add 
a. add 
a. add 
a. add 
a. add 
args 
argument(" --nb_epoch", default=NB_EPOCHS) 
argument(" - -batch_size", default-BAT _ SIZE) 
argument(" 
-output_model_file", default=" inceptionv3-ft. model") 
argument(" - -plot", action="store_true") 
if args . train_dir is None or args.val_dir is None: 
sys. exit(l) 
if, (not os.path.exists(args . train_dir)) (not os . path.exists(args.val dir)): 
print("directories do not exist") 
sys. exit(l) 
train (args)

 

argparse 라는 녀석으로 쉽게 argument 를 설정할 수 있나보다

--train_dir

--val_dir

--nb_epoch

--batch_size

--output_model_file

--plot

train set 위치

val 위치

default epoch 3. *nb number 를 의미하는듯

default batch_size 32

default "inceptionv3-ft.model" // 저장하고픈 이름 설정도 가능

action = "store_true"

 

1) 최소한 --train_dir --val_dir은 지정해줘야 한다

2) 최소한 지정한 두 path 가 실제로 존재해야 한다

 

train(args) 실행

 

실제 train 아래와 같이 실행함

- python3 fine-tune.py --train_dir ~/kaggle-dogcat/train_dir/ --val_dir ~/kaggle-dogcat/val_dir/

- 데이터들은 아래와 같이 저장되어 있다.

- train , validation 용으로 크게 구분하며

- cat, dog 폴더 이름 자체가 class 의 라벨이 되고

- 폴더 안에는 각각 cat, dog 이미지들이 들어있다

: "kaggIeI/DeepLearningSandbox/transfer learning$ 
tree —d 
kagg le — dogca t 
tes t I 
train dir 
val di r 
dog

 

 

train(args) 함수

시스템 생성 대체 텍스트:
101 
104 
10년 
110 
111 
def train(args) : 
"Use transfer learning and fine-tuning to train network on a new dataset" 
nb train_samples = get nb files(args•train dir) 
nb [1B55E5 = len(glob•glob(args•train dir + "/*”)) 
nb val_samples = get nb files(args•val dir) 
nb_epoch = int(args • nb_epoch) 
batch size = int(args. batch size) 
data prep 
train datagen = ImageDataGenerator( 
55 ng_f 55 _input , 
rotatlon range=3e, 
width shift range=e.2, 
height shift range=e.2, 
shear range=e. 2, 
200m range=e . 2』 
horizontal flip—True 
test datagen 1 = ImageDataGenerator( 
55 ng_f 55 _input , 
rotatlon range=3e, 
width shift range=e.2, 
height shift range=e.2, 
shear range=e. 2, 
200m range=e . 2』 
horizontal flip—True 
trainGenerator = train datagen. 十10년 from directory( 
argS. d , 
target_size=(IM WIDTH, 1M HEIGHT) , 
batch size—batch size, 
validation_generator = test datagen. 十101•』 from directory[d 
args•val dir, 
target_size=(IM WIDTH, 1M HEIGHT) , 
batch size—batch size,

 

train 위한 정보들 정리해둠

1) nb_train_samples

- get_nb_files() 함수는 해당 디렉토리의 모든 파일 개수를 리턴해줌 (recursively)

2) nb_classes

- glob.glob() 함수로 train_dir 아래의 파일또는 디렉토리의 개수를 리턴

- 따라서 cat, dog가 있으니 2개의 class 가 있다는 것임

3) nb_val_samples

 - get_nb_files() 함수는 해당 디렉토리의 모든 파일 개수를 리턴해줌 (recursively)

4) nb_epoch, batch_size 역시 argument 로 넘어온 값을 변수에 넣어둠

 

data prep

- 데이터를 augmentation (=조금 만져서 개수 늘리기) 하기 위한 함수를 생성하는 것으로 보임

- 실제로 데이터가 늘어난다기 보다는 매 학습시마다 변형을 준다

1) train_datagen, test_datagen 두 함수를 동일하게 생성

2) 전처리 함수는 preprocess_input (인셉션v3 패키지에서 제공하는 듯)

3) augmentation 방법은

- 돌리기, 종횡으로 옮기기, 짜부라트리기, 확대하기, 수평으로 뒤집기

 

 

 

 

 

 

 

 

실제 데이터 생성하는 레시피 작성

1) 위에서 만든 전처리 함수 train_datagen, test_datagen 으로

2) train_dir, val_dir 에 있는 이미지들을

3) 해상도 299x299, 배치사이즈 32로 만들어서 실제로 돌리기 좋게 해둠

 

 

 

시스템 생성 대체 텍스트:
11? 
114 
115 
11년 
# 5은tu다 "10de1 
base model = InceptionV3(weights= • • , include top=Fa1se) 
취nclude top=Fa1se excludes final FC layer 
model = add new last layer(base model, nb [1B55은5)

 

 

setup model

1) 베이스가 되는 모델은

- imagenet 데이터셋으로

- InceptionV3 라는 CNN 모델을 train weight를 가져온다

- 가장 마지막 (=top) 레이어는 가져오지 않는다. 이녀석은 FC layer 이다

 

2) 베이스를 기반으로 새로 만든 모델은

- base_model 에 이어붙인뒤 마지막 레이어가 nb_classes (= dog, cat = 2) 인 모델

- add_new_last_layer() 함수는 (별도로 조금 자세히봐도 좋겠지만 일단)

1) base_model.out = 마지막으로 내보내는 값을 받아서

2) GlobalAveragePooling2D() 를 해준다음

3) Dense = FC 를 해준다. FC_SIZE = 1024개로 해줌

4) Dense = FC 를 한 번 더해주는데 이번에는 softmax 를 해서 예측하도록 한다

- 예측값은 predictions 에 넣어준다

5) 드디어, 새로운 모델을 만들어서, 그 모델을 리턴해주게 된다

*keras 2 버전에서 바뀐것들: https://github.com/keras-team/keras/releases/tag/2.0.0

Model() 함수에서

input inputs

output outputs

118 
119 
123 
121 
122 
123 
124 
125 
126 
127 
# transfer learning 
setup_to_transfer_learn(model, base_model) 
history_tl = model. fit_generator( 
train_generator , 
nb_epoch=nb_epoch, 
samples_pe 
validation_data=validation_generator, 
nb_val_samples=nb_val_samples, 
class_weight= ' auto' )

 

Keras 2에서 변경

118 
119 
123 
121 
122 
123 
124 
125 
126 
127 
# transfer learning 
setup_to_transfer_learn(model, base_model) 
history_tl = model. fit_generator( 
train_generator , 
epochs = nb_epoch , 
n_samples/ batch_size , 
validation_data=validation_generator, 
validation_steps=nb_val_samples, 
class_weight= ' auto ' )

 

transfer learning

1) setup_to_transfer_learn() 함수

- base_model 인 인셉션의 모든 레이어들에 대해

- 추가 학습이 되지 않게 = weight 값 변하지 않게 설정

- optimizer, loss, metrics 를 설정

2) fit_generator() 함수

- 보통은 fit() 함수로 학습시키지만

- generator 로 생성한 데이터를 학습시킬때는 fit_generator() 함수로 학습시킨다

1) train 할 데이터를 생성하는건 train_generator

2) epoch 학습할지, epoch 마다의 데이터 개수

3) validate 할 데이터를 생성하는건 valitation_generator

4) valitation 데이터 개수

5) class_weight 는 아마도 class 들간의 데이터 개수 불균형에 대한 조정방법인듯

 

*keras 2 버전에서 바뀐것들: https://github.com/keras-team/keras/releases/tag/2.0.0

- samples_per_epoch steps_per_epoch (=samples_per_epoch / batch_size)

- nb_epoch epochs

- nb_val_samples validation_steps

123 
131 
132 
133 
134 
136 
137 
138 
# fine-tuning 
(model) 
history_ft = model. fit_generator( 
train_generator , 
nb_epoch=nb_epoch, 
validation_data=validation_generator, 
nb_val_samples=nb_val_samples, 
class_weight= ' auto' )

 

Keras 2에서 변경

129 
131 
132 
133 
134 
136 
137 
138 
# fine-tuning 
(model) 
history_ft = model. fit_generator( 
train_generator , 
nb_epoch=nb_epoch, 
validation_data=validation_generator, 
nb_val_samples=nb_val_samples, 
class_weight= ' auto' )

 

fine-tuning

- 일단 위에서 transfer learning model을 가져와서 다시 학습한다

1) setup_to_finetune() 함수

- 172 레이어까지는 trainable = False, 즉 초기 레이어들은 여전히 학습시키지 말고

- 172 부터는 기존 인셉션 v3 레이어도 trainable = True

- optimizer learning_rate, momentum 설정, loss, metrics 설정

2) 마찬가지로 fit_generator() 함수로 학습

 

*keras 2 버전에서 바뀐것들: https://github.com/keras-team/keras/releases/tag/2.0.0

- samples_per_epoch steps_per_epoch (=samples_per_epoch / batch_size)

- nb_epoch epochs

- nb_val_samples validation_steps

 

Ice 
141 
142 
model. save(args. output_model_file) 
, if args . plot: 
plot_training(history_ft)

 

1) 여기까지 학습이 완료된 모델을 save

 

2) plot_training()

 - args.plot 은 따로 argument를 안넣었으니 실행안됨

- GCE에서 matplotlib을 쓰려면 어케하면 될까?

 

소스 기타 함수 분석

def 
les (directory) : 
""Get number of files by, searching, directory, recursively" 
, if onot os. path .exists(directory) : 
return e 
cnt = e 
for r, dirs. files in Ts .walk(directory): 
for dr in dirs: 
cnt len(glob.glob(os . path. join(r, dr + 
return cnt

 

1) 파라미터로 넘어온 디렉토리를

2) recursive 하게 돌면서

3) 전체 파일 개수를 리턴해준다

def add_new_last_layer(base_model, nb_classes): 
"""Add, last layer to the convnet 
Args : 
base model : 
nb classes: 
Returns : 
keras model excluding top 
classes 
new keras model with last layer 
x— base_model.output 
x— GlobalAverageP001ing2D() (x) 
x = Dense(FC_SIZE, activation='relu ' *new, FCO layer, , random init 
predictions = Dense(nb_classes, activation=' softmax• )(x) 
softmax layer 
model = model(inputs=base_model. input, outputs—predictions) 
return model

 

1) base_model.out = 마지막으로 내보내는 값을 받아서

2) GlobalAveragePooling2D() 를 해준다. 참고링크 CNN에서의 FC vs average pooling

3) Dense = FC 를 해준다. activation function relu. FC_SIZE = 1024개로 해줌

4) Dense = FC 를 해준다. activation function softmax 를 써서 확률이 나오도록 함

- 예측값은 predictions 에 넣어준다

- 예측값은 확률이니 모든 클래스의 예측값을 더해주면 1이 된다

5) 드디어, 새로운 모델을 만들어서, 그 모델을 리턴해주게 된다

 

 

*keras 2 버전에서 바뀐것들: https://github.com/keras-team/keras/releases/tag/2.0.0

line 54 Model() 함수에서

input inputs

output outputs

 

def setup_to_transfer_learn(model, base_model): 
Freeze all layers and compile the model" 
for , layer in base_model.layers: 
layer. trai nable 
False 
model. compile(optimizer= rmsprop ' 
loss= ' categorical_crossentropy ' 
accuracy ] )

 

1) base_model = 인셉션 v3

2) 모든 레이어의 trainable = False

- , 우리의 새로운 dog, cat dataset 으로 추가 학습이 일어나지 않도록 한다

3) optimizer, loss, metrics 를 설정한다

 

def : 
""" Freeze the bottom NB_IV3 LAYERS and retrain the remaining top layers. 
onote: INB IV3 LAYERS corresponds to the topo inceptior' blocks iri the inceptionv3 arch 
Args : 
model: keras rnodel 
for layer in model. layers[ TO_FREEZE]: 
layer. trainable = 
False 
for Aayer in model. 
layer. trainable = 
True 
model. oøel, momentum=e. 9), 
loss= ' categori cal_crossentropy ' 
metrics=[ ' accuracy ' ] )

 

1) base_model = 인셉션 v3

2) 172 레이어부터는 trainable = True

- , 우리의 새로운 dog, cat dataset 으로

- 172 레이어 이후만 추가 학습이 일어나도록 한다

3) optimizer, loss, metrics 를 설정한다

147 
148 
Ise 
Iss 
157 
158 
161 
def : 
acc = history.history[ 'acc'] 
val_acc = history. history[ 'val_acc•] 
loss 
= history. history[ ' loss • ] 
val loss 
= history. history[ 'val_loss'] 
epochs — 
range(len(acc)) 
plt.plot(epochs, acc, 
plt.plot(epochs, val_acc, 
plt.title( 'Training and validation accuracy' ) 
plt. figure() 
plt.plot(epochs, loss, 
plt.plot(epochs, val_loss, 
plt.title( 'Training and validatiom loss' ) 
plt. show()

 

matplotlib 으로 학습과정을 시각화 해주는 함수

 

1) 코드에서는 transfer learning 은 생략하고

2) fine-tuning 부분만 보여주게 해두었다.

- fine-tune.py 함수도 주피터에서 실행하면 되긴 하겠다

 

 

실행 - trial and error

 

실행방법

python3 fine-tune.py --train_dir ~/kaggle-dogcat/train_dir/ --val_dir ~/kaggle-dogcat/val_dir/

 

1) 데이터셋만 가져다두고, 실행시 옵션에 넣어주기만 하면 된다

2) 모델의 학습이 완료되면 (save 되면 model 명을 명시하지 않으면) inceptionv3-ft.model 라는 파일로 저장된다 

 

기존 소스를 Keras 2 맞게 수정해줘야 한다.

 

*기존 keras 1소스 그대로 했을 경우 warning

fine—tune .py:S4: UserWarning: Update your •Model • call to the Keras 2 
Tensor ("in. ) 
model = Model (input—base model . input, output—predictions) 
fine—tune .py: 126: UserWarning: The semantics of the Keras 2 argument 
API : 
•Model (outputs=Tensor ("de. . 
inpu t s = 
•steps per epoch • is not the same as the Ke 
ras I argument •samples per epoch • 
•steps per epoch • is the number of batches to draw from the generator at eac 
h epoch. Basically steps per epoch = samples per epoch/ batch size. Similarly • nb val samples • •validation steps 
•val samples • —Y steps • arguments have changed. Update your method calls accordingly. 
class weight=' auto') 
fine—tune . py: 126: UserWarning: Update your 
class 
steps per epoch=7SO, 
class weight=' auto') 
• fit generator • call to the Keras 2 API: 
validation . pre. . 
epochs=3 , 
• fit generator (<keras . pre. . 
validation steps—1000)

 

*keras 2 버전에서 바뀐것들: https://github.com/keras-team/keras/releases/tag/2.0.0

Model() 함수

input inputs

output outputs

 

fit_generator() 함수

- samples_per_epoch steps_per_epoch (=samples_per_epoch / batch_size)

- nb_epoch epochs

- nb_val_samples validation_steps

 

학습 도중 Ctrl-z 아닌 Ctrl-c 나와야 한다

 

- Ctrl-z 로 나오면, 프로세스 자체가 종료된게 아니라 계속 메모리를 잡아먹어, 다양한 문제가 발생한 것으로 보임

 

에러1. Resource exhausted: OOM when allocating tensor with shape

에러2. Error in `python3': double free or corruption

 

 

Microsoft OneNote 2016에서 작성